#include "smartalloc_wrap.h"
#include <iomanip>
#include <tr1/memory>

#include "dispatcher.h"
#include "invoker.h"
#include "serializer.h"
#include "Serializable.h"

using namespace std;
using namespace TTP;

class meep : public Serializable {
public:
   int iv;

   meep() {}

   meep(int v) : iv(v) {}

   virtual void fromVec(std::vector<byte>::const_iterator &vit,
    const std::vector<byte>::const_iterator &end) {
      iv = *vit++;
   }

   virtual void toVec(std::vector<byte> &vec) const {
      vec.push_back(iv);
   }
};

class foo : public Serializable {
public:
   string word;

   foo() {}

   foo(const char* w) : word(w) {}

   virtual void fromVec(std::vector<byte>::const_iterator &vit,
    const std::vector<byte>::const_iterator &end) {
      int siz = *vit++;
      word.append(vit, vit+siz);
      vit += siz;
   }

   virtual void toVec(std::vector<byte> &vec) const {
      vec.push_back(word.length());
      vec.insert(vec.end(), word.begin(), word.end());
   }
};

void funk(meep m1, const meep& m2, const foo& f1, 
      const string& s, int i, bool b) {
   cout << m1.iv << " " << m2.iv << " " << f1.word << " " << s << " " << i << " " 
      << (b ? "yes!" : "no") << endl;
}

int fib(int n) {
   int a = 1, b = 1;
   for (int i = 3; i <= n; i++) {
      int c = a + b;
      a = b;
      b = c;
   }           
   return b;
}

void happy(const int &i, const string& f) {
   cout << f << fib(i) << endl;
}

void noarg() {
   cout << "meep\n";
}


class fake_state : public dispatcher {

public:
   fake_state() {
      Register(this, &fake_state::meth1);
      Register(this, &fake_state::meth2);
   }
   
   void doCalls() {
      call_remote(&fake_state::meth1, "happy are us!");
      call_remote(&fake_state::meth2, "Method: ", 2);
      call_remote(&fake_state::meth1, "happy are us!");
      call_remote(&fake_state::meth2, "Method: ", 2);
   }

   void recvCalls() {
      shared_ptr<vector<byte>> vec(getBuffer());
      applyVector(*vec);
      call_remote(&fake_state::meth2, "Method: ", 2);
      // no leaks
   }

   void meth1(const string& val) {
      cout << val << endl;
   }

   void meth2(foo val, const meep i) {
      cout << val.word << i.iv << endl;
   }

};

namespace TTP {
   int supertest() {
      dispatcher d;     
      d.Register(funk); 
      d.Register(happy);
      d.Register(noarg);

      d.call_remote(funk, 1, 2, "foo", "'Hello, this is a long test'", 100, 1); 
      d.call_remote(happy, 20, "The 20th fibonacci number is: "); 

      shared_ptr<vector<byte>> vec(d.getBuffer());
      d.applyVector(*vec);

      d.call_remote(happy, 20, string("The 20th fibonacci number is: ")); 
      d.call_remote(funk, 1, meep(2), "foo", "'Hello, this is a long test'", 100, false); 
      d.call_remote(noarg); 

      vec = shared_ptr<vector<byte>>(d.getBuffer());
      d.applyVector(*vec);

      d.call_remote(funk, 1, meep(2), "foo", "'Hello, this is a long test'", 100, false); 
         // no leaks
   }
}

int main () {
   supertest();

   fake_state f;
   f.doCalls();
   f.recvCalls();
}
